#include <dspSimulator/instruction/subaw.h>


bool SUBAW::checkCondition(std::shared_ptr<DspMachine> dspMachine) {
    if (isCompactInstruction) {
        return true;
    } else {
        return checkStandardCondition(dspMachine);
    }
}

void SUBAW::loadInstIRIntoJit(llvm::LLVMContext *llvmContext, llvm::Module *module,
                              std::shared_ptr<llvm::IRBuilder<>> irBuilder) {

}

std::shared_ptr<Instruction> SUBAW::decode(std::shared_ptr<InstInfo> instInfo, u64 baseCycle) {
    std::shared_ptr<SUBAW> subaw;
    auto dspInstInfo = std::dynamic_pointer_cast<DspInstInfo>(instInfo);
    bool isStandardInst = dspInstInfo->isStandardInstruction();
    if (isStandardInst) {

    } else {
        auto data = vectorToBitSet<16>(dspInstInfo->getBits());
        if (checkBits<3>(data, 10, 0b011) && data[7] == 1 && checkBits<7>(data, 0, 0b1110111)) {
            subaw = std::make_shared<SUBAW>(dspInstInfo->getAddress(),baseCycle);
            subaw->isCompactInstruction = true;
            subaw->compactInstKind = "Dx5p";
            subaw->src1 = extractBits<3>(data, 13).to_ulong();
            subaw->src1 += extractBits<2>(data, 8).to_ulong() << 3;
            subaw->src2 = 15;
            subaw->dst = 15;
            subaw->s = 1;
            subaw->funcUnit = FuncUnit::S2;
            subaw->DSZ = dspInstInfo->getDSZ();
            subaw->RS = dspInstInfo->getRS();
            subaw->SAT = dspInstInfo->getSAT();
            subaw->PROT = dspInstInfo->getPROT();
            subaw->BR = dspInstInfo->getBR();
            subaw->p = dspInstInfo->getP();
            subaw->fixUpRegOnCompactInstruction();
            subaw->instFormat = InstFormat::Kind2;
        }
    }
    return subaw;
}

void SUBAW::executeCustom(std::shared_ptr<TargetMachine> targetMachine, ExecutePhase executePhase) {
    auto dspMachine = std::dynamic_pointer_cast<DspMachine>(targetMachine);
    u32 op2;
    if (instFormat == InstFormat::Kind1) {
        op2 = *src1LoRegPtr << 2;
    } else if (instFormat == InstFormat::Kind2) {
        op2 = src1 << 2;
    }
    if (src2 >= 4 && src2 <= 7) {
//        循环寻址
        if (s == 0) {
            auto adddrMode = dspMachine->getRegAAddressingMode(src2);
            if (adddrMode == AddressingMode::Linear) {
                *dstLoRegPtr = *src2LoRegPtr - op2;
            } else if (adddrMode == AddressingMode::CircularBK0) {
                auto blockSize = dspMachine->getAMRBlockSize(0);
                *dstLoRegPtr = *src2LoRegPtr + blockSize - op2;
            } else if (adddrMode == AddressingMode::CircularBK1) {
                auto blockSize = dspMachine->getAMRBlockSize(1);
                *dstLoRegPtr = *src2LoRegPtr + blockSize - op2;
            }
        } else {
            auto adddrMode = dspMachine->getRegBAddressingMode(src2);
            if (adddrMode == AddressingMode::Linear) {
                *dstLoRegPtr = *src2LoRegPtr - op2;
            } else if (adddrMode == AddressingMode::CircularBK0) {
                auto blockSize = dspMachine->getAMRBlockSize(0);
                *dstLoRegPtr = *src2LoRegPtr + blockSize - op2;
            } else if (adddrMode == AddressingMode::CircularBK1) {
                auto blockSize = dspMachine->getAMRBlockSize(1);
                *dstLoRegPtr = *src2LoRegPtr + blockSize - op2;
            }
        }
    } else {
        // 线性寻址
        *dstLoRegPtr = *src2LoRegPtr - op2;
    }
}

std::string SUBAW::toString() const {
    std::string res;
    if (!isCompactInstruction) {
        res += getStandardConditionString() + " ";
    }
    res += m_name + " " + FuncUnitName[static_cast<u32>(funcUnit)] + " ";
    if (instFormat == InstFormat::Kind1) {
        res += getSrc2Reg32Name() + "," + getSrc1Reg32Name() + "," + getDstReg32Name();
    } else if (instFormat == InstFormat::Kind2) {
        res += getSrc2Reg32Name() + "," + std::to_string(src1) + "," + getDstReg32Name();
    }

    return res;
}

std::shared_ptr<DspInstruction> SUBAW::clone() {
    return std::make_shared<SUBAW>(*this);
}
